package com.dony.shop.service.impl;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.dony.common.core.domain.entity.SysUser;
import com.dony.common.core.redis.RedisCache;
import com.dony.common.utils.SecurityUtils;
import com.dony.common.utils.StringUtils;
import com.dony.shop.domain.ShopeeMerchant;
import com.dony.shop.domain.ShopeeShop;
import com.dony.shop.service.IShopeeMerchantService;
import com.dony.shop.service.IShopeeShopService;
import com.dony.shop.service.ShopeeAuthService;
import com.dony.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service("shopeeAuthService")
public class ShopeeAuthServiceImpl implements ShopeeAuthService {

    @Value("${shopee.parent_id}")
    private Integer parentId;
    @Value("${shopee.key}")
    private String key;
    @Value("${shopee.api_host}")
    private String host;
    @Value("${website.uri}")
    private String uri;
    @Autowired
    RedisCache redisCache;
    @Autowired
    IShopeeShopService shopService;
    @Autowired
    IShopeeMerchantService merchantService;
    @Autowired
    ISysUserService userService;

    /**
     * 定时刷新token
     */
    public void refreshAllTonken() {
        //更新所有的主账户
        List<ShopeeMerchant> merchants = merchantService.list();
        merchants.stream().forEach(merchant -> {
            refreshAccessTokenByMerchantId(merchant.getLastRefreshToken(), merchant.getMerchantId());
        });
        //更新所有的店铺
        List<ShopeeShop> shops = shopService.list();
        shops.stream().forEach(shop -> {
            refreshAccessTokenByShopId(shop.getLastRefreshToken(), shop.getShopId());
        });
    }


    @Override
    public String createAccessTokenUrl() {
        long timestamp = System.currentTimeMillis() / 1000L;
        String path = "/api/v2/shop/auth_partner";
        String baseString = parentId + path + timestamp;
        //加密的sign
        String sign = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(baseString);
        String url = host + path + "?partner_id=" + parentId + "&redirect=http://" + uri + "/octv-prod-api/shopee/auth/saveAccessToken/" + SecurityUtils.getUserId() + "&timestamp=" + timestamp + "&sign=" + sign;
        //log.info("Shopee 授权链接:" + url);
        return url;
    }


    @Override
    public void saveAccessToken(String code, Long mainAccountId, Long shopId, Long userId) {
        //主账户登录
        if (mainAccountId != null) {
            processMerchantFirstResult(code, mainAccountId, userId);
        } else if (shopId != null) {
            processShopFirstToken(code, shopId, userId);
        }
    }

    /**
     * 获取主账户 保存返回的第一对access_token与refresh_token
     *
     * @param code
     * @param mainAccountId
     * @return
     */
    public void processMerchantFirstResult(String code, Long mainAccountId, Long userId) {
        long timestamp = System.currentTimeMillis() / 1000L;
        String path = "/api/v2/auth/token/get";
        JSONObject params = new JSONObject();
        params.put("partner_id", parentId);
        params.put("code", code);
        params.put("main_account_id", mainAccountId);
        String baseString = parentId + path + timestamp;
        String sign = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(baseString);
        String url = host + path + "?partner_id=" + parentId + "&timestamp=" + timestamp + "&sign=" + sign;
        String postResult = HttpUtil.post(url, params.toString());
        JSONObject reslut = JSONObject.parseObject(postResult);
        if (StringUtils.isNotEmpty(reslut.getString("error"))) {
            log.error("商户获取授权信息失败！商户ID:{}", mainAccountId);
            return;
        }
        //处理结果
        List<Long> shopIdList = reslut.getList("shop_id_list", Long.class);
        String refreshToken = reslut.getString("refresh_token");
        //更新中国卖家的信息
        List<Long> merchants = reslut.getList("merchant_id_list", Long.class);
        Long merchantId = merchants.get(0);
        //保存商户信息
        saveMerchainInfo(mainAccountId, userId, merchantId);
        //刷新商户的token
        refreshAccessTokenByMerchantId(refreshToken, merchantId);
        //更新商户信息
        updateMerchantInfo(merchantId);
        //更新子店铺的信息
        shopIdList.forEach(shopItem -> {
            //保存店铺信息
            saveShopInfo(mainAccountId, userId, shopItem, merchantId);
            //刷新店铺的token
            refreshAccessTokenByShopId(refreshToken, shopItem);
            //更新店铺信息
            updateShopInfo(shopItem);
        });

    }

    /**
     * 获取店铺授权
     * 保存返回的第一对access_token与refresh_token
     *
     * @param code
     * @param shopId
     * @return
     */
    public void processShopFirstToken(String code, Long shopId, Long userId) {
        long timestamp = System.currentTimeMillis() / 1000L;
        String path = "/api/v2/auth/token/get";
        JSONObject params = new JSONObject();
        params.put("partner_id", parentId);
        params.put("code", code);
        params.put("shop_id", shopId);
        String baseString = parentId + path + timestamp;
        String sign = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(baseString);
        String url = host + path + "?partner_id=" + parentId + "&timestamp=" + timestamp + "&sign=" + sign;
        String postResult = HttpUtil.post(url, params.toString());
        JSONObject reslut = JSONObject.parseObject(postResult);
        if (StringUtils.isNotEmpty(reslut.getString("error"))) {
            log.error("店铺获取授权信息失败！店铺ID:{}", shopId);
            return;
        }
        String refreshToken = reslut.getString("refresh_token");
        String accessToken = reslut.getString("access_token");

        //保存店铺信息
        ShopeeShop shop = shopService.getById(shopId);
        if (shop == null || shop.getShopId() == null) {
            shop = new ShopeeShop();
            shop.setShopId(shopId);
        }
        SysUser user = userService.selectUserById(userId);
        if (user != null) {
            shop.setTenantId(user.getDeptId());
        }
        shop.setUserId(userId);
        shop.setAuth(true);
        shop.setDelFlat("0");
        shopService.saveOrUpdate(shop);
        //刷新店铺的token
        refreshAccessTokenByShopId(refreshToken, shopId);
        //更新店铺信息
        updateShopInfo(shopId);
    }


    /**
     * 设置店铺信息
     *
     * @param shopId
     */
    private void updateShopInfo(Long shopId) {
        long timestamp = System.currentTimeMillis() / 1000L;
        String path = "/api/v2/shop/get_shop_info";
        String accessToken = getShopAccessToken(shopId);
        String baseString = parentId + path + timestamp + accessToken + shopId;
        String sign = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(baseString);
        String url = host + path + "?partner_id=" + parentId + "&timestamp=" + timestamp + "&access_token=" + accessToken + "&shop_id=" + shopId + "&sign=" + sign;
        String postResult = HttpUtil.get(url);
        JSONObject info = JSONObject.parseObject(postResult);
        if (StringUtils.isNotEmpty(info.getString("error"))) {
            log.error("店铺信息获取失败！店铺ID:{}", shopId);
            return;
        }
        //这里一定会有值
        ShopeeShop shop = shopService.getByShopId(shopId);
        shop.setShopName(info.getString("shop_name"));
        shop.setRegion(info.getString("region"));
        shop.setStatus(info.getString("status"));
        shop.setIsCb(info.getBoolean("is_cb"));
        shop.setIsCnsc(info.getBoolean("is_cnsc"));
        shop.setShopCbsc(info.getString("shop_cbsc"));
        shop.setIs3pf(info.getBoolean("is_3pf"));
        shop.setRequestId(info.getString("request_id"));
        //处理时间信息
        if (info.getLong("auth_time") != null) {
            shop.setAuthTime(new Date(info.getLong("auth_time") * 1000L));
        }
        if (info.getLong("expire_time") != null) {
            shop.setExpireTime(new Date(info.getLong("expire_time") * 1000L));
        }
        shop.setIsSip(info.getBoolean("is_sip"));
        shopService.updateById(shop);
    }


    /**
     * 设置中国卖家信息
     * /get_merchant_info
     *
     * @param merchantId
     */
    private void updateMerchantInfo(Long merchantId) {
        long timestamp = System.currentTimeMillis() / 1000L;
        String path = "/api/v2/merchant/get_merchant_info";
        String accessToken = getMerchantAccessToken(merchantId);
        String baseString = parentId + path + timestamp + accessToken + merchantId;
        String sign = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(baseString);
        String url = host + path + "?partner_id=" + parentId + "&timestamp=" + timestamp + "&access_token=" + accessToken + "&merchant_id=" + merchantId + "&sign=" + sign;
        String postResult = HttpUtil.get(url);
        JSONObject info = JSONObject.parseObject(postResult);
        if (StringUtils.isNotEmpty(info.getString("error"))) {
            log.error("中国卖家信息获取失败！商户ID:{}", merchantId);
            return;
        }
        //这里一定会有值
        ShopeeMerchant merchant = merchantService.getByMerchantId(merchantId);
        merchant.setMerchantName(info.getString("merchant_name"));
        merchant.setIsCnsc(info.getBoolean("is_cnsc"));
        //处理时间信息
        if (info.getLong("auth_time") != null) {
            merchant.setAuthTime(new Date(info.getLong("auth_time") * 1000L));
        }
        if (info.getLong("expire_time") != null) {
            merchant.setExpireTime(new Date(info.getLong("expire_time") * 1000L));
        }
        merchant.setRequestId(info.getString("request_id"));
        merchant.setMerchantCurrency(info.getString("merchant_currency"));
        merchant.setMerchantRegion(info.getString("merchant_region"));
        merchant.setIsUpgradedCbsc(info.getBoolean("is_upgraded_cbsc"));
        merchantService.updateById(merchant);
    }


    /**
     * 保存店铺的信息
     *
     * @param userId
     * @param shopId
     * @param merchantId
     */
    public void saveShopInfo(Long mainAccountId, Long userId, Long shopId, Long merchantId) {
        ShopeeShop shop = shopService.getById(shopId);
        if (shop == null || shop.getShopId() == null) {
            shop = new ShopeeShop();
            shop.setShopId(shopId);
        }
        SysUser user = userService.selectUserById(userId);
        if (user != null) {
            shop.setTenantId(user.getDeptId());
        }
        shop.setUserId(userId);
        shop.setMainAccountId(mainAccountId);
        shop.setMerchantId(merchantId);
        ShopeeMerchant merchant = merchantService.getByMerchantId(merchantId);
        if (merchant != null) {
            shop.setMerchantName(merchant.getMerchantName());
        }
        shop.setAuth(true);
        shop.setDelFlat("0");
        shopService.saveOrUpdate(shop);
    }

    /**
     * 保存店铺的信息
     *
     * @param userId
     * @param merchanId
     */
    public void saveMerchainInfo(Long mainAccountId, Long userId, Long merchanId) {
        ShopeeMerchant merchant = merchantService.getByMerchantId(merchanId);
        if (merchant == null || merchant.getMerchantId() == null) {
            merchant = new ShopeeMerchant();
            merchant.setMerchantId(merchanId);
        }
        SysUser user = userService.selectUserById(userId);
        if (user != null) {
            merchant.setTenantId(user.getDeptId());
        }
        merchant.setUserId(userId);
        merchant.setMainAccountId(mainAccountId);
        merchant.setAuth(true);
        merchant.setDelFlat("0");
        merchantService.saveOrUpdate(merchant);
    }


    @Override
    public String getShopAccessToken(Long shopId) {
        String accessToken = redisCache.getCacheObject("shopee:access_token:shop_" + shopId);
        if (StringUtils.isEmpty(accessToken)) {
            synchronized (this) {
                accessToken = redisCache.getCacheObject("shopee:access_token:shop_" + shopId);
                if (StringUtils.isEmpty(accessToken)) {
                    log.info("缓存失效，请求shopee刷新，并更新数据库refreshToken！店铺ID：{}", shopId);
                    String refreshToken = shopService.selectLastRefreshToken(shopId);
                    return refreshAccessTokenByShopId(refreshToken, shopId);
                }
            }
        }
        return accessToken;
    }


    @Override
    public String getMerchantAccessToken(Long merchantId) {
        String accessToken = redisCache.getCacheObject("shopee:access_token:merchant_" + merchantId);
        if (StringUtils.isEmpty(accessToken)) {
            synchronized (this) {
                accessToken = redisCache.getCacheObject("shopee:access_token:merchant_" + merchantId);
                if (StringUtils.isEmpty(accessToken)) {
                    log.info("缓存失效，请求shopee刷新，并更新数据库refreshToken！商家ID：{}", merchantId);
                    String refreshToken = merchantService.selectLastRefreshToken(merchantId);
                    return refreshAccessTokenByMerchantId(refreshToken, merchantId);
                }
            }
        }
        return accessToken;
    }


    /**
     * @param refreshToken
     * @param shopId
     * @return
     */
    public String refreshAccessTokenByShopId(String refreshToken, Long shopId) {
        long timestamp = System.currentTimeMillis() / 1000L;
        String path = "/api/v2/auth/access_token/get";
        JSONObject params = new JSONObject();
        params.put("refresh_token", refreshToken);
        params.put("partner_id", parentId);
        params.put("shop_id", shopId);
        String baseString = parentId + path + timestamp;
        String sign = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(baseString);
        String url = host + path + "?partner_id=" + parentId + "&timestamp=" + timestamp + "&sign=" + sign;
        String postResult = HttpUtil.post(url, params.toString());
        JSONObject reslut = JSONObject.parseObject(postResult);
        if (StringUtils.isNotEmpty(reslut.getString("error"))) {
            log.error("错误：刷新店铺 token 失败 shopid:{}", shopId);
            shopService.setAuth(shopId,false);
            log.error("错误信息：{}", postResult);
            return null;
        }else {
            shopService.setAuth(shopId,true);
        }
        String refresh = reslut.getString("refresh_token");
        String accessToken = reslut.getString("access_token");
        //更新数据库
        UpdateWrapper<ShopeeShop> wrapper = new UpdateWrapper<>();
        wrapper.set("last_refresh_token", refresh).eq("shop_id", shopId);
        shopService.update(wrapper);
        redisCache.setCacheObject("shopee:access_token:shop_" + shopId, accessToken, 3, TimeUnit.HOURS);
        return accessToken;
    }


    public String refreshAccessTokenByMerchantId(String refreshToken, Long merchantId) {
        long timestamp = System.currentTimeMillis() / 1000L;
        String path = "/api/v2/auth/access_token/get";
        JSONObject params = new JSONObject();
        params.put("refresh_token", refreshToken);
        params.put("partner_id", parentId);
        params.put("merchant_id", merchantId);
        String baseString = parentId + path + timestamp;
        String sign = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(baseString);
        String url = host + path + "?partner_id=" + parentId + "&timestamp=" + timestamp + "&sign=" + sign;
        String postResult = HttpUtil.post(url, params.toString());
        JSONObject reslut = JSONObject.parseObject(postResult);
        if (StringUtils.isNotEmpty(reslut.getString("error"))) {
            log.error("错误：刷新商家 token 失败 merchantId:{},错误信息：{}", merchantId, postResult);
            merchantService.setAuth(merchantId,false);
            return null;
        }else {
            merchantService.setAuth(merchantId,true);
        }
        String refresh = reslut.getString("refresh_token");
        String accessToken = reslut.getString("access_token");
        //更新数据库
        UpdateWrapper<ShopeeMerchant> wrapper = new UpdateWrapper<>();
        wrapper.set("last_refresh_token", refresh).eq("merchant_id", merchantId);
        merchantService.update(wrapper);
        redisCache.setCacheObject("shopee:access_token:merchant_" + merchantId, accessToken, 3, TimeUnit.HOURS);
        return accessToken;
    }
}
